/***************************************************************************** 
** XXX nand_spl/board/infotm/imapx/boot_main.c XXX
** 
** Copyright (c) 2009~2014 ShangHai Infotm Ltd all rights reserved. 
** 
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** Description: The first C function in PRELOADER.
**
** Author:
**     Warits   <warits.wang@infotm.com>
**      
** Revision History: 
** ----------------- 
** 1.1  XXX 03/17/2010 XXX	Warits
*****************************************************************************/

#include <common.h>
#include <asm/io.h>
#include <nand.h>
#include "preloader.h"

void boot_set_stat(uint16_t stat)
{
	*(uint16_t *)CONFIG_SYS_PHY_BOOT_STAT = stat;
}

void boot_set_stat2(uint16_t stat)
{
	*(uint16_t *)(CONFIG_SYS_PHY_BOOT_STAT + 2) = stat;
}

/**
 * memcpy - Copy one area of memory to another
 * @dest: Where to copy to
 * @src: Where to copy from
 * @count: The size of the area.
 *
 * You should not use this function to access IO space, use memcpy_toio()
 * or memcpy_fromio() instead.
 */
void * memcpy(void * dest,const void *src,size_t count)
{
	char *tmp = (char *) dest, *s = (char *) src;

	count >>= 2;
	while (count--)
	{
		*(uint32_t *)tmp = *(uint32_t *)s;
		tmp += 4;
		s   += 4;
	}

	return dest;
}

void nor_boot(void)
{
	__attribute__((noreturn)) void (*uboot)(void)
		= (void *)(CONFIG_SYS_DISK_U_BOOT_DST + 0x40);

#ifdef CONFIG_SYS_NOR_RC
	/* set nor para */
	writel((readl(EMCPC_BASE_REG_PA + 0x94) & ~0x3f)
	   | CONFIG_SYS_NOR_RC, EMCPC_BASE_REG_PA + 0x94);
#endif

	memcpy((uchar *)(CONFIG_SYS_DISK_U_BOOT_DST + 0x40), (uint8_t *)(CONFIG_SYS_DISK_U0_OFFS + 0x10000000),
	   CONFIG_SYS_DISK_U_BOOT_SIZE);

	(*uboot)();
}

#if 0

uint32_t nand_get_boot_para(int para_no)
{

	uint32_t *boot_para = (uint32_t *)(CONFIG_AU_CLK_MAGIC_OFFS | (1 << 31));
	
	return boot_para[para_no]; 
}

uint32_t nand_save_boot_para(void)
{
	uint32_t *boot_spl = (uint32_t *)CONFIG_SYS_PHY_UBOOT_SWAP;
	uint32_t ret = 0;
	uint32_t *boot_para = 0;

	struct nand_chip nand_chip;
	nand_info_t nand_info;	
	
	nand_info.priv = &nand_chip;
        nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = (void  __iomem *)CONFIG_SYS_NAND_BASE;
        nand_chip.dev_ready = NULL;     /* preset to NULL */

        /* Call board specific init function */
        board_nand_init(&nand_chip);

        if (nand_chip.select_chip)
               nand_chip.select_chip(&nand_info, 0);


        ret = nand_load(&nand_info, 0, 512*1024,(uchar *)boot_spl);

	boot_para = boot_spl + 8192 - 64;

	if(nand_get_boot_para(4) != CONFIG_AU_MEMPOOL_MAGIC)
	{
		boot_para[4] = CONFIG_AU_MEMPOOL_MAGIC;
		/* save memory settings */
		boot_para[7] = CONFIG_AU_MEM_MAGIC;
		boot_para[0x8] = readl(DENALI_CTL_PA_62);
		boot_para[0x9] = readl(DENALI_CTL_PA_63);
		boot_para[0xa] = readl(DENALI_CTL_PA_64);
		boot_para[0xb] = readl(DENALI_CTL_PA_65);
		boot_para[0xc] = readl(DENALI_CTL_PA_66);
		boot_para[0xd] = readl(DENALI_CTL_PA_67);
		boot_para[0xe] = readl(DENALI_CTL_PA_68);
		boot_para[0xf] = readl(DENALI_CTL_PA_69);
	}

	ret = imap_nand_write_buf(&nand_info, (u_char *)boot_spl, 512*1024);
		


}
#endif

void boot_main(void)
{
	__attribute__((noreturn)) void (*uboot)(void);

 
	uboot = 0;

	/* Call board specific init function */

#if defined(CONFIG_MEM_POOL)
	/* Check reset status */
	imapx200_check_reset();

	/* enable mmu & cache */
	mmu_table_init();

	/* Init GPIOs */
	imapx200_init_gpio();

	/* Init timer if a clean boot */
	timer_init();
#endif

//	mmu_stop();
//        while(1);
	/* First we try if USB is connected */
#if !defined(CONFIG_DISABLE_BOOT_OTG) && !defined(CONFIG_SYS_BOOT_NOR) && 0


	if(!usb_otg_check())
	  goto __nand_boot__;

	/* Load u-boot.img from USB */
	if(usb_otg_load())
	  goto __nand_boot__;

	/* Check img validity */
	uboot = check_ubimg();
	if(!uboot)
	  goto __nand_boot__;

	boot_set_stat(CONFIG_BOOTSTAT_USB);
	(*uboot)();

__nand_boot__:
#endif


	/*
#ifdef CONFIG_BOOT_AUTO_ADJUST
	if(readl(INFO2) == CONFIG_AU_MEM_MAGIC)
		denali_study();
	else
		*(uint32_t *)(0x40008000) = 0;
	writel(0,INFO2);
#endif
*/
	mmu_start();



#ifndef CONFIG_SYS_BOOT_NOR
	nand_boot();
#else
	nor_boot();
#endif
}
